<template>
  <div class="modal-wrapper" v-loading="loading">
    <div class="draw-container">
      <div class="draw-content" :style="{ width: containerWidth, height: containerHeight }">
        <canvas class="canvas" ref="canvas"></canvas>
        <div
          class="mark rect"
          :class="{ 'active': item.active }"
          v-for="(item, index) in labelList"
          :key="index"
          :style="{
            left: item.startX + 'px',
            top: item.startY + 'px',
            width: (item.endX - item.startX) + 'px',
            height: (item.endY - item.startY) + 'px',
            borderColor: color,
            color: color,
          }">
          <div>{{item.label}}</div>
        </div>
        <canvas
          class="canvasBak"
          ref="canvasBak"
          :style="{cursor: curcursor}"
          @mousedown="mousedown"
          @mouseup="mouseup"
          @mousemove="mousemove">
        </canvas>
      </div>
      <div class="draw-tool">
        <el-table
          class="table"
          :data="labelList"
          style="width: 100%"
          :max-height="300">
          <el-table-column label="标签名" prop="label" show-overflow-tooltip></el-table-column>
          <el-table-column label="操作" width="60">
            <template slot-scope="scope">
              <el-button type="text" size="mini" @click="deleteRow(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
    <mine-dialog :appendToBody="true" :dialogFormVisible="flag" :width="'600px'" :modalFlag="modalFlag" :title="title" :showClose="showClose" @close="close">
      <addLabel ref="addLabel" v-if="assembly === '新增标签'" slot="option" :flag="flag" @close="close" :imageInfo="imageInfo" :labelInfo="labelInfo" @submit="addLabelCallback" @cancel="addLabelCancelCallback"></addLabel>
    </mine-dialog>
  </div>
</template>
<script>
import { modalMixins } from '../../mixins.js';
import addLabel from './addLabel.vue';
import { omit } from 'lodash';

const DEFAULT_CANVAS = {
  width: 600,
  height: 600
};

export default {
  mixins: [modalMixins],
  components: {
    addLabel,
  },
  props: {
    source: {
      type: String,
      default: ''
    },
    imageInfo: {
      type: Object,
      default: function () { return {}; }
    }
  },
  computed: {
    curcursor () {
      return this.source ? 'crosshair' : 'auto';
    },
    containerWidth () {
      return `${this.canvasSize.width}px`;
    },
    containerHeight () {
      return `${this.canvasSize.height}px`;
    }
  },
  data () {
    return {
      curFun: 'rect',
      color: '#54e346',
      penSize: 1, // 线框宽度
      canvas: this.$refs.canvas, // 底层
      context: null,
      canvasBak: this.$refs.canvasBak, // 上层模板
      contextBak: null,
      canvasSize: {
        width: 0,
        height: 0,
      },
      ratio: 0,
      startX: 0,
      startY: 0,
      endX: 0,
      endY: 0,
      isClick: false,
      canDraw: false,
      canvasLeft: 0,
      canvasTop: 0,
      labelList: [],
      loading: false,
      isAddingLabel: false,
    };
  },
  methods: {
    initCanvas () {
      this.canvas = this.$refs.canvas;
      this.canvas.width = DEFAULT_CANVAS.width;
      this.canvas.height = DEFAULT_CANVAS.height;
      this.context = this.canvas.getContext('2d');

      this.canvasBak = this.$refs.canvasBak;
      this.canvasBak.width = DEFAULT_CANVAS.width;
      this.canvasBak.height = DEFAULT_CANVAS.height;
      this.contextBak = this.canvasBak.getContext('2d');

      // canvas在文本的位置
      const pos = this.canvas.getBoundingClientRect();
      this.canvasLeft = pos.left;
      this.canvasTop = pos.top;
    },
    init () {
      this.canDraw = false;
      this.clearContext(true);
      this.labelList = [];
      // this.clearPoint();
      this.drawPic();
    },
    drawPic () {
      this.clear();
      const image = new Image();
      image.src = this.source;
      image.onload = () => {
        const canvasWidth = DEFAULT_CANVAS.width;
        const canvasHeight = DEFAULT_CANVAS.height;
        const imageWidth = image.width;
        const imageHeight = image.height;
        const isHorizontal = imageWidth >= imageHeight;
        let drawWidth = 0;
        let drawHeight = 0;
        let drawStart = 0;
        let drawEnd = 0;
        let ratio = 0;
        if (isHorizontal) {
          ratio = canvasWidth / imageWidth;
          drawWidth = canvasWidth;
          drawHeight = imageHeight * ratio;
        } else {
          ratio = canvasHeight / imageHeight;
          drawHeight = canvasHeight;
          drawWidth = imageWidth * ratio;
        }
        this.ratio = ratio;
        this.canvasSize.width = drawWidth;
        this.canvasSize.height = drawHeight;
        this.resizeCanvas();
        this.context.drawImage(
          image,
          0,
          0,
          imageWidth,
          imageHeight,
          0,
          0,
          drawWidth,
          drawHeight
        );
        this.initLabel();
      };
    },
    async initLabel () {
      this.loading = true;
      const params = {
        picId: this.imageInfo.id
      };
      try {
        const res = await this.$store.dispatch('tagAdminCalibrationLoadOnePicLabels', params);
        const result = res.data || {};
        if (result.success) {
          const data = result.data && result.data.length ? result.data : [];
          const list = data.map(item => {
            let startX = 0, startY = 0, endX = 0, endY = 0;
            const label = item.classifyName;
            const point = item.points.replace(/[()]/g, '').replace(/\|/g, ',').split(',').map(item => parseFloat(item));
            startX = point[0] ? point[0] * this.ratio : 0;
            startY = point[1] ? point[1] * this.ratio : 0;
            endX = point[2] ? point[2] * this.ratio : 0;
            endY = point[3] ? point[3] * this.ratio : 0;
            return {
              ...item,
              label,
              startX,
              startY,
              endX,
              endY
            };
          });
          this.labelList = list;
        } else {
          this.labelList = [];
        }
      } catch (e) {
        console.error(e);
      }

      this.loading = false;
    },
    resizeCanvas () {
      this.canvas.width = this.canvasSize.width;
      this.canvas.height = this.canvasSize.height;
      this.canvasBak.width = this.canvasSize.width;
      this.canvasBak.height = this.canvasSize.height;
    },
    clear () {
      this.clearContext(true);
    },
    /**
     * 清空canvas内容
     * @param  {[Boolean]} flag true: canvas 和 canvasBak都清除，false：只清除canvasBak
     */
    clearContext (flag) {
      this.contextBak.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);
      if (flag) {
        this.context.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);
      }
    },
    clearPoint () {
      this.startX = 0;
      this.startY = 0;
      this.endX = 0;
      this.endY = 0;
    },
    handleContainerMouseup () {
      if (!this.isAddingLabel) {
        this.clearContext();
        this.clearPoint();
        this.canDraw = false;
      }
    },
    mousedown (e) {
      this.stopDefault(e);
      if (!this.source) return;
      const pos = this.canvas.getBoundingClientRect();
      this.canvasLeft = pos.left;
      this.canvasTop = pos.top;
      this.contextBak.strokeStyle = this.color;
      this.contextBak.lineWidth = this.penSize;

      this.startX = e.clientX - this.canvasLeft;
      this.startY = e.clientY - this.canvasTop;
      this.canDraw = true;
      this.isClick = true;
    },
    mouseup (e) {
      this.stopDefault(e);
      this.canDraw = false;
      if (!this.isClick) {
        this.addLabel();
      }
    },
    mousemove (e) {
      this.stopDefault(e);
      this.isClick = false;
      let x = e.clientX - this.canvasLeft;
      let y = e.clientY - this.canvasTop;
      const startX = this.startX;
      const startY = this.startY;
      if (this.canDraw) {
        if (this.curFun === 'rect') {
          this.contextBak.beginPath();
          this.clearContext();
          this.contextBak.moveTo(startX, startY);
          this.contextBak.lineTo(x, startY);
          this.contextBak.lineTo(x, y);
          this.contextBak.lineTo(startX, y);
          this.contextBak.lineTo(startX, startY);
          this.contextBak.stroke();
          this.endX = x;
          this.endY = y;
        }
      }
    },
    stopDefault (e) {
      e.stopPropagation();
    },
    // 选完框后，添加标签
    addLabel () {
      const startX = this.startX <= this.endX ? this.startX : this.endX;
      const startY = this.startY <= this.endY ? this.startY : this.endY;
      const endX = this.endX >= this.startX ? this.endX : this.startX;
      const endY = this.endY >= this.startY ? this.endY : this.startY;
      this.labelInfo = {
        ratio: this.ratio,
        startX,
        startY,
        endX,
        endY,
      };
      this.flag = true;
      this.showClose = true;
      this.title = '新增标签';
      this.assembly = '新增标签';
      this.$nextTick(() => {
        this.$refs.addLabel.show();
      });
      this.isAddingLabel = true;
    },
    addLabelCallback () {
      this.initLabel();
      this.isAddingLabel = false;
    },
    addLabelCancelCallback () {
      this.clearContext();
      this.isAddingLabel = false;
    },
    close () {
      this.flag = false;
      this.isAddingLabel = false;
      this.clearContext();
    },
    deleteRow1 (val) {
      const idx = this.labelList.findIndex(item => {
        return item.startX === val.startX &&
          item.startY === val.startY &&
          item.endX === val.endX &&
          item.endY === val.endY;
      });
      if (idx !== -1) {
        this.labelList.splice(idx, 1);
      }
    },
    async deleteRow (val) {
      const params = {
        calibrationDetailId: val.calibrationDetailId,
        calibrationId: val.calibrationId,
        picId: val.picId,
        classifyId: val.classifyId,
      };
      try {
        const res = await this.$store.dispatch('tagAdminCalibrationDeleteImgDetectLabel', params);
        const result = res.data || '';
        if (result.success) {
          this.$message({ type: 'success', message: '删除成功' });
          this.initLabel();
        } else {
          this.$message({ type: 'error', message: '删除失败' });
        }
      } catch (e) {
        console.error(e);
      }
    },
    getResult () {
      const result = this.labelList.map(item => {
        let { createTime, classifyId, calibrationId, startX, startY, endX, endY, label } = item;
        startX = (startX / this.ratio).toFixed(2);
        startY = (startY / this.ratio).toFixed(2);
        endX = (endX / this.ratio).toFixed(2);
        endY = (endY / this.ratio).toFixed(2);
        const points = `(${startX},${startY})|(${endX},${endY})`;
        const row = {
          ...omit(item, ['label', 'startX', 'startY', 'endX', 'endY', 'ratio']),
          classifyName: label,
          points: item.points ? item.points : points, // 如果之前已有坐标，则使用之前的
        };
        if (calibrationId) row.calibrationId = calibrationId;
        if (classifyId) row.classifyId = classifyId;
        row.createTime = createTime || this.$common.format(new Date(), 'yyyy-MM-dd');
        return row;
      });
      return result;
    },
  },
  mounted () {
    this.initCanvas();
    document.addEventListener('mouseup', this.handleContainerMouseup);
  },
  beforeDestroy () {
    document.removeEventListener('mouseup', this.handleContainerMouseup);
  }
}
</script>
<style lang="less" scoped>
  .draw-container {
    width: 100%;
    display: flex;
    justify-content: space-between;
  }
  .draw-content {
    width: 100%;
    position: relative;
    z-index: 1;
    overflow: hidden;
    canvas {
      position: absolute;
      left: 0;
      top: 0;
      &.canvas {
        z-index: -1;
      }
      &.canvasBak {
        z-index: 9999;
      }
    }
  }
  .mark {
    position: absolute;
    box-sizing: border-box;
    border: 1px solid #54e346;
    font-size: 14px;
  }
  .draw-tool {
    width: 200px;
  }
</style>
